package io.gitee.zhangbinhub.admin.oauth.service

import com.mybatisflex.core.query.QueryWrapper
import io.gitee.zhangbinhub.acp.boot.exceptions.WebException
import io.gitee.zhangbinhub.admin.common.constant.RoleCode
import io.gitee.zhangbinhub.admin.oauth.base.OauthBaseService
import io.gitee.zhangbinhub.admin.oauth.entity.*
import io.gitee.zhangbinhub.admin.oauth.po.RolePo
import io.gitee.zhangbinhub.admin.oauth.repo.*
import io.gitee.zhangbinhub.admin.resource.server.vo.RoleVo
import org.noear.solon.annotation.Component
import org.noear.solon.annotation.Inject
import org.noear.solon.data.annotation.Transaction

@Component
open class RoleService(
    @Inject userRepository: UserRepository,
    private val roleRepository: RoleRepository,
    private val roleMenuRepository: RoleMenuRepository,
    private val roleModuleFuncRepository: RoleModuleFuncRepository,
    private val userRoleRepository: UserRoleRepository
) : OauthBaseService(userRepository) {

    @Throws(WebException::class)
    fun getRoleList(): MutableList<Role> =
        roleRepository.selectListByQuery(QueryWrapper.create().orderBy(Role::sort).asc())

    @Throws(WebException::class)
    fun getRoleVoList(): MutableList<RoleVo> = getRoleList().map { item ->
        RoleVo(
            id = item.id,
            appId = item.appId,
            code = item.code,
            levels = item.levels,
            name = item.name,
            sort = item.sort,
            type = item.type,
            userIds = item.userSet.map { it.id }.toMutableList(),
            menuIds = item.menuSet.map { it.id }.toMutableList(),
            moduleFuncIds = item.moduleFuncSet.map { it.id }.toMutableList()
        )
    }.toMutableList()

    @Throws(WebException::class)
    fun getRoleListByAppId(loginNo: String, appId: String): List<Role> {
        val user = getUserInfoByLoginNo(loginNo) ?: throw WebException("无法获取当前用户信息")
        return if (isSuper(user)) {
            roleRepository.selectListByQuery(
                QueryWrapper.create().where(Role::appId).eq(appId)
                    .orderBy(Role::sort).asc()
            )
        } else {
            roleRepository.selectListByQuery(
                QueryWrapper.create().where(Role::appId).eq(appId)
                    .and(Role::levels).gt(getRoleMinLevel(appId, user))
                    .orderBy(Role::sort).asc()
            )
        }
    }

    @Throws(WebException::class)
    private fun doSave(userInfo: User, role: Role, rolePo: RolePo): Role =
        (if (rolePo.userIds.isNotEmpty()) {
            userRepository.selectListByIds(rolePo.userIds)
        } else {
            mutableListOf()
        }).let { userSetPo ->
            if (validateModifyUserSet(userInfo, role.userSet, userSetPo)) {
                role.copy(
                    name = rolePo.name!!,
                    code = rolePo.code!!,
                    sort = rolePo.sort,
                    levels = rolePo.levels,
                    type = rolePo.type
                ).also {
                    roleRepository.insertOrUpdate(it)
                }.also {
                    roleMenuRepository.deleteByQuery(QueryWrapper.create().where(RoleMenu::roleId).eq(it.id))
                    roleModuleFuncRepository.deleteByQuery(
                        QueryWrapper.create().where(RoleModuleFunc::roleId).eq(it.id)
                    )
                    userRoleRepository.deleteByQuery(QueryWrapper.create().where(UserRole::roleId).eq(it.id))
                    if (rolePo.menuIds.isNotEmpty()) {
                        roleMenuRepository.insertBatch(rolePo.menuIds.map { id ->
                            RoleMenu(menuId = id, roleId = it.id)
                        })
                    }
                    if (rolePo.moduleFuncIds.isNotEmpty()) {
                        roleModuleFuncRepository.insertBatch(rolePo.moduleFuncIds.map { id ->
                            RoleModuleFunc(moduleId = id, roleId = it.id)
                        })
                    }
                    if (rolePo.userIds.isNotEmpty()) {
                        userRoleRepository.insertBatch(rolePo.userIds.map { id ->
                            UserRole(userId = id, roleId = it.id)
                        })
                    }
                }
            } else {
                throw WebException("不合法的操作，不允许修改更高级别的用户列表！")
            }
        }

    @Transaction
    @Throws(WebException::class)
    open fun doCreate(loginNo: String, rolePo: RolePo): Role =
        getUserInfoByLoginNo(loginNo)?.let { userInfo ->
            if (!isSuper(userInfo)) {
                val currLevel = getRoleMinLevel(rolePo.appId!!, userInfo)
                if (currLevel >= rolePo.levels) {
                    throw WebException("没有权限做此操作，角色级别必须大于 $currLevel")
                }
            }
            if (rolePo.code == RoleCode.SUPER) {
                throw WebException("不允许创建超级管理员")
            }
            doSave(userInfo, Role(appId = rolePo.appId!!), rolePo)
        } ?: throw WebException("无法获取当前用户信息")

    @Transaction
    @Throws(WebException::class)
    open fun doDelete(loginNo: String, idList: MutableList<String>) {
        val user = getUserInfoByLoginNo(loginNo) ?: throw WebException("无法获取当前用户信息")
        if (!isSuper(user)) {
            val roleMinLevel = getRoleMinLevel(user)
            val roleList = roleRepository.selectListByIds(idList)
            roleList.forEach {
                if (!roleMinLevel.containsKey(it.appId) || roleMinLevel.getValue(it.appId) >= it.levels) {
                    throw WebException("没有权限做此操作")
                }
            }
        }
        roleMenuRepository.deleteByQuery(QueryWrapper.create().where(RoleMenu::roleId).`in`(idList))
        roleModuleFuncRepository.deleteByQuery(
            QueryWrapper.create().where(RoleModuleFunc::roleId).`in`(idList)
        )
        userRoleRepository.deleteByQuery(QueryWrapper.create().where(UserRole::roleId).`in`(idList))
        roleRepository.deleteBatchByIds(idList)
    }

    @Transaction
    @Throws(WebException::class)
    open fun doUpdate(loginNo: String, rolePo: RolePo): Role =
        getUserInfoByLoginNo(loginNo)?.let { userInfo ->
            val role = roleRepository.selectOneWithRelationsById(rolePo.id!!)
            if (!isSuper(userInfo)) {
                val currLevel = getRoleMinLevel(role.appId, userInfo)
                if (currLevel > 0 && currLevel >= rolePo.levels) {
                    throw WebException("没有权限做此操作，角色级别必须大于 $currLevel")
                }
                if (currLevel > 0 && currLevel >= role.levels) {
                    throw WebException("没有权限做此操作，请联系系统管理员")
                }
            } else {
                if (rolePo.code != role.code && role.code == RoleCode.SUPER) {
                    throw WebException("超级管理员编码不允许修改")
                }
                if (rolePo.levels != role.levels && role.levels <= 0) {
                    throw WebException("超级管理员级别不允许修改")
                }
                if (rolePo.levels != role.levels && rolePo.levels <= 0) {
                    throw WebException("不允许修改为超级管理员级别[" + rolePo.levels + "]")
                }
            }
            doSave(userInfo, role, rolePo)
        } ?: throw WebException("无法获取当前用户信息")

    @Throws(WebException::class)
    fun getRoleInfo(roleId: String): RoleVo =
        roleRepository.selectOneWithRelationsById(roleId).let { item ->
            RoleVo(
                id = item.id,
                appId = item.appId,
                code = item.code,
                levels = item.levels,
                name = item.name,
                sort = item.sort,
                type = item.type,
                userIds = item.userSet.map { it.id }.toMutableList(),
                menuIds = item.menuSet.map { it.id }.toMutableList(),
                moduleFuncIds = item.moduleFuncSet.map { it.id }.toMutableList()
            )
        }
}
